using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using NBusiness.Query;

namespace NBusiness.Data.Providers.SqlServer.Query
{
    public enum AliasAssignmentStyle
    {
        Unique,
        TableName,
        None
    }

    public sealed class SqlQueryContext : IQueryContext
    {
        private AliasAssignmentStyle _aliasStyle;
        private Hashtable _aliases = new Hashtable();
        private uint _aliasCount;

        public AliasAssignmentStyle AliasStyle
        {
            get { return _aliasStyle; }
        }

        /// <summary>
        /// Create a new query context. Alias assignment is on by default.
        /// </summary>
        public SqlQueryContext() 
            : this(AliasAssignmentStyle.Unique) 
        { }
        /// <summary>
        /// Create a new query context. Alias assignment is on by default.
        /// </summary>
        /// <param name="assignAliases">
        /// Set this to false to disable alias assignment.
        /// </param>
        public SqlQueryContext(AliasAssignmentStyle aliasStyle)
        {
            _aliasStyle = aliasStyle;
        }

        internal string EnsureAlias(ISource source)
        {
            string alias = null;

            if (AliasStyle == AliasAssignmentStyle.Unique)
            {
                ITable table = source as ITable;
                if (table != null)
                    RegisterAlias(table.Name);

                if (string.IsNullOrEmpty(source.Alias))
                    source.Alias = GetNextAlias();

                alias = source.Alias;
                RegisterAlias(source.Alias);
            }
            else if(AliasStyle == AliasAssignmentStyle.TableName)
            {
                ITable table = source as ITable;
                if (table != null)
                {
                    alias = table.Name;
                }
            }

            return alias;
        }

        private string GetNextAlias()
        {
            string alias = null;
            while (alias == null || _aliases.ContainsKey(alias))
            {
                alias = ConvertToBase26(_aliasCount++);
            }
            return alias;
        }

        private void RegisterAlias(string alias)
        {
            if (!_aliases.ContainsKey(alias))
                _aliases.Add(alias, 1);
        }

        private string ConvertToBase26(uint i)
        {
            char c = (char)((i % 26) + 65);
            return (i < 26 ? c.ToString() : ConvertToBase26(i / 26) + c.ToString());
        }
    }
}
